#!/bin/bash

### BEGIN INFO
#
# $Id. Yongjian Xu <i3dmaster@gmail.com> $
# $Version: 0.3.4 $
# $ This source code maintained by svn at <http://code.google.com/p/scan-network/> $
#
# Copyright (C) 2006 Yongjian Xu

## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
#
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
#
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
#
# Provides:          scan_network
# Required:          Bash - this program used process substitution. Normal sh will not support this feature.
# Required-Start:    S06DSSLV-disks. This tool *MUST* run after the diskmount for the home user device
#                    if home is a writable device in LiveCD env. On a local system, this is not required.
# Required-Stop:
# Default-Start:     rcS.d/S11scan_network
# Default-Stop:      optional: rc0.d/K11scan_network
#                    rc6.d/K11scan_network
# Short-Description: scan avail networks and populate interfaces file.
# Description:       
#                    
# ToDo: 1. LiveCD detection. -done
#       2. Daemon support (log support).
#       3. A possible force keyword support in profile file to let user force using a saved config
#       4. wpasupplicant support
#       5. GUI support.
#                    
# Comments: This script is having problem running under virtual machine
#           since the the network interfaces under vm are virtual devices.
#           mii-tool will report error.
#
### END INIT INFO

#For debug purpose
export RUNDIR="/etc/network/scan_network"
#[[ -f $RUNDIR/scan_network.debug ]] && rm -f $RUNDIR/scan_network.debug
#touch $RUNDIR/scan_network.debug

set -e

. /lib/lsb/init-functions
. /etc/default/scan_network

(
################ LiveCD support ##########################
export LIVECD=""
export LIVEUSER=""

if [[ "$LIVECD" != "" ]]; then
        if [[ ! -e /home/$LIVEUSER/.scan_network ]]; then
                mkdir -p /home/$LIVEUSER/.scan_network
                cp /etc/network/scan_network/* /home/$LIVEUSER/.scan_network
                
        fi
        export CFG_DIR="/home/$LIVEUSER/.scan_network"
else
        export CFG_DIR="/etc/network/scan_network"
fi
export ETH_CFG="$CFG_DIR/eth.cfg"
export WIFI_CFG="$CFG_DIR/wifi.cfg"
#########################################################
#
export IFACEFILE="/etc/network/interfaces"
export IFSTATE="/etc/network/run/ifstate"
export ORIGFILE="$CFG_DIR/interfaces.orig"
[[ ! -f $ORIGFILE ]] && log_failure_msg "FATAL: No $ORIGFILE file found under $CFG_DIR. Exit." && exit 1
export BKUPFILE="$CFG_DIR/.interfaces.scan_network.bk"
export ETH_TOOL=${ETH_TOOL:-/sbin/mii-tool}
export WIFI_TOOL=${WIFI_TOOL:-/sbin/iwlist}
export WIFI_CONFIG_TOOL=${WIFI_CONFIG_TOOL:-/sbin/iwconfig}
export IFCONFIG=${IFCONFIG:-/sbin/ifconfig}
export LOGFILE=${LOGFILE:-/var/log/scan_network.log}
DHCLIENT=${DHCLIENT:-/sbin/dhclient}
[[ -f /etc/dhclient.conf ]] && DHCFG="/etc/dhclient.conf"
LS=${LS:-/bin/ls}
GREP=${GREP:-/bin/grep}
PS=${PS:-/bin/ps}
XARGS=${XARGS:-/usr/bin/xargs}
#
#
# Define ANSI colors
export NORMAL="\033[0;39m"
export RED="\033[1;31m"
export GREEN="\033[1;32m"
export BLUE="\033[1;34m"
export YELLOW="\033[1;33m"
export MAGENTA="\033[1;35m"
export CYAN="\033[1;36m"
export WHITE="\033[1;37m"
export END="\033[0m"
#
# Init some variables
export E_DEV=""
export E_CMD=""
export W_DEV=""

alter_dhcfg() {
        if [[ $DHCFG ]]; then
                _defint=$(cat $DHCFG | $GREP "initial-interval" | awk '{print $2}')
                echo "${_defint/;/}" >$RUNDIR/.dhcfg
                sed -i '/initial-interval/{s/^#//;s/[0-9]\+/0/}' $DHCFG
                #echo "the content of $RUNDIR/.dhcfg is $(cat $RUNDIR/.dhcfg)"
        else
                echo -e "${YELLOW}$DHCFG not found. Unable to probe wireless networks."
                return 1
        fi
}

#sleep 10

start_scan () {
    log_action_begin_msg "Scan networking starting"
    #Everytime when scan_network starts, always make sure it starts from the orig file which have nothing configured in it.
    cp $IFACEFILE $BKUPFILE
    cp $ORIGFILE $IFACEFILE
    
    #sleep 10

    #Check if any eth interfaces are connected with cable.
    #Its possible that wireless card is also having an ethx name.
    ( $WIFI_CONFIG_TOOL >$RUNDIR/.iwconfig ) 2>/dev/null
    #echo "The content of $RUNDIR/.iwconfig is $(cat $RUNDIR/.iwconfig)"
    W_DEV=$(cat $RUNDIR/.iwconfig | $GREP "ESSID" | awk '{print $1}')
    if [[ $W_DEV != "" ]]; then
        while read eth_dev; do
            if [[ ! $($ETH_TOOL $eth_dev | $GREP "no link") ]]; then
                E_DEV="$E_DEV $eth_dev"
                E_CMD="iface $eth_dev inet dhcp\nup ifconfig $eth_dev mtu 1400\n\n$E_CMD"
            fi
        done < <($LS -d /sys/class/net/*/device | $GREP eth \
                | sed 's/.*net\///g;s/\/.*//g' | $GREP -v "$W_DEV")
    else
        while read eth_dev; do
            if [[ ! $($ETH_TOOL $eth_dev | $GREP "no link") ]]; then
                E_DEV="$E_DEV $eth_dev"
                E_CMD="iface $eth_dev inet dhcp\nup ifconfig $eth_dev mtu 1400\n\n$E_CMD"
            fi
        done < <($LS -d /sys/class/net/*/device | $GREP eth | sed 's/.*net\///g;s/\/.*//g')
    fi
    
    #sleep 10

    #If eth card(s) connected.
    if [[ x"$E_DEV" != "x" ]]; then
        sed -i 's/auto lo/& '"$E_DEV"'/' $IFACEFILE
        echo >>$IFACEFILE
        #If eth.cfg file isn't configured.
        if [[ ! $(cat $ETH_CFG | $GREP -v '^#') ]]; then
            echo -e "$E_CMD" >>$IFACEFILE
        else
            for iface in $(echo $E_DEV); do
                #If eth.cfg is configured but this iface isn't.
                if [[ ! $(cat $ETH_CFG | sed -n '/^#\|^$/!p' | $GREP  $iface) ]]; then
                    echo -e "iface $iface inet dhcp\nup ifconfig $iface mtu 1400\n\n" >>$IFACEFILE
                else
                    i=2;a="\t1. DHCP"
                    while read line; do
                        a="$a\n\t$i. $line"; i=$((i+1))
                    done < <(cat $CFG_DIR/eth.cfg | $GREP -v '^#' | $GREP '|' | $GREP $iface | awk -F: '{print $1}'| sed 's/|//')
                    unset i
                    echo
                    echo -e "\n${CYAN}$a${END}"
                    #start_count=$(date +%s)
                    while read -t 10 -p "Ethernet profile to use(pick number)[enter or 1 is the default]: " choice; do
                        case $choice in
                            ""|1)   echo -e "iface $iface inet dhcp\nup ifconfig $iface mtu 1400\n\n" >>$IFACEFILE 
                                    break
                                    ;;
                            [2-9])  if [[ $(echo -e "$a" | $GREP $choice) ]]; then 
                                        profile=$(echo -e "$a" | $GREP $choice | awk '{print $2}')
                                        cat $ETH_CFG | sed -n '/^#\|^$/!p' \
                                        | awk -v i=$iface -v l=$profile \
                                        'BEGIN{FS="[|]";RS=""};{for(k=1;k<=NF;k++) \
                                        {if((index($k,i))&&(index($k,l)))p=$k}};END{print p}' \
                                        | sed 's/'"$profile"': //g' \
                                        >>$IFACEFILE
                                        echo >>$IFACEFILE
                                        break
                                    else
                                        echo "${RED}No such choice.${END}"
                                    fi
                                    ;; 
                            *)      echo "Unknown choice"
                                    ;;
                        esac
                        #end_count=$(date +%s)
                        #if (( $end_count - $start_count > 5 )); then
                        #    echo -e "${YELLOW}\tDHCP is assumed for this device $iface ... {END}"
                        #    echo -e "iface $iface inet dhcp\nup ifconfig $iface mtu 1400\n\n" >>$IFACEFILE
                        #    break
                        #fi
                    done
                    if [[ ! $choice ]]; then
                        echo
                        echo -e "${YELLOW}\tDHCP is assumed for this device $iface ... ${END}"
                        echo -e "iface $iface inet dhcp\nup ifconfig $iface mtu 1400\n\n" >>$IFACEFILE
                    fi
                fi
            done
        fi
    fi

    #sleep 10

    #If there is a wireless device, probe the wireless env around.
    if [[ $W_DEV != "" ]] && alter_dhcfg ;then 
        [[ -f /etc/resolv.conf ]] && cp /etc/resolv.conf /etc/resolv.conf.bk
        echo
        echo -e "${YELLOW}Probing wireless network around this area ...${END}"
        echo
        $DHCLIENT -e $(echo $W_DEV|head -1) 2>/dev/null 1>/dev/null &
        sleep 5
        ( $PS -aef | $GREP "$DHCLIENT" | $GREP "$(echo $W_DEV|head -1)" | awk '{print $2}' | $XARGS -ti kill -9 {} ) 2>/dev/null 1>/dev/null
        #sleep 10
        DEFINT=$(cat $RUNDIR/.dhcfg)
        #echo "DEFINT is $DEFINT"
        sed -i '/initial-interval/{s/^/#/;s/[0-9]\+/'"$DEFINT"'/}' $DHCFG
        unset DEFINT
        ( $WIFI_TOOL scanning >$RUNDIR/.iwlist.scan ) 2>/dev/null
        #echo "The content of $RUNDIR/.iwlist.scan is $(cat $RUNDIR/.iwlist.scan)"
        $IFCONFIG $(echo $W_DEV|head -1) down 2>/dev/null 1>/dev/null
        [[ -f /etc/resolv.conf.bk ]] && mv /etc/resolv.conf.bk /etc/resolv.conf
        if [[ ! -s $RUNDIR/.iwlist.scan ]]; then
                echo "${YELLOW}No wireless network detected${END}"
                exit 0
        fi
    #sleep 20

    if [[ ! $(cat $RUNDIR/.iwlist.scan | $GREP -i "No Scan") ]]; then
            #cat $RUNDIR/.iwlist.scan && sleep 30
            cat $RUNDIR/.iwlist.scan | awk 'BEGIN{FS="Cell "; RS=""};{for(i=2;i<=NF;i++)print $i >"'$RUNDIR'/."i-1".scan"}'
            #pick the strongest one to access
            #sleep 40
            if [[ $(echo $(ls $RUNDIR/.[1-9]*.scan|wc -l)) -eq 1 ]]; then
                wifi_info=$(cat .1.scan) 
            else
                wifi_info=$(cat $($GREP -iw quality $RUNDIR/.[1-9]*.scan \
                | sort -t'=' -k2.1nr | awk '{$1=gensub(":","","g",$1);print $1}' | head -1))
            fi
            #echo "the wifi_info is $wifi_info"
            ESSID=$(echo $wifi_info| $GREP 'ESSID' | awk -F\" '{print $2}')
            #MODE=$(echo $wifi_info | $GREP 'Mode' | awk -F: '{print $2}')
            KEY=$(echo $wifi_info | $GREP 'Encryption' | awk -F: '{print $2}')
            if [[ ! $(cat $WIFI_CFG | $GREP -v '^#' | $GREP "$ESSID") ]]; then 
                if [[ x$KEY = "xoff" ]]; then
                    sed -i 's/auto lo/& '"$W_DEV"'/' $IFACEFILE    
                    echo >>$IFACEFILE
                fi
                for i in $(echo $W_DEV); do
                    echo -e "iface $i inet dhcp\n\tup ifconfig $i mtu 1400\n" >>$IFACEFILE
                    echo -e "\twireless-mode managed\n" >>$IFACEFILE
                    echo -e "\twireless-essid $ESSID\n" >>$IFACEFILE
                    echo >>$IFACEFILE
                done
            else
                 #Not considering the situation where different physical place having the same ESSID. 
                 #For example, Home with ESSID "foo" and Office having the same ESSID "foo". 
                 #Although its possible, but would be very very rare.
                    sed -i 's/auto lo/& '"$W_DEV"'/' $IFACEFILE
                    cat $WIFI_CFG | sed -n '/^#\|^$/!p' \
                    | awk -v i=$ESSID \
                    'BEGIN{FS="[|]";RS=""};{for(k=1;k<=NF;k++) \
                    {if(index($k,i))p=$k}};END{print p}' \
                    | sed 's/^[^ ]*: //g' \
                    >>$IFACEFILE
            fi
           
    fi
    fi
    #sleep 20
    #cat $IFACEFILE
    #sleep 50

#[[ ! -d $RUNDIR/.debug ]] && mkdir -p $RUNDIR/.debug && echo "Creating debug dir"
#mv $RUNDIR/.*.scan $RUNDIR/.iwconfig $RUNDIR/.dhcfg $RUNDIR/.debug
#sleep 20
rm -fr $RUNDIR/.*.scan $RUNDIR/.iwconfig $RUNDIR/.dhcfg 2>/dev/null
log_end_msg 0
}
 
stop_scan () {
    cp $ORIGFILE $IFACEFILE
    [[ -f /var/run/scan_network.pid ]] && kill -15 $(cat /var/run/scan_network.pid) 2>/dev/null 1>/dev/null
}

case $1 in
    start|restart|reload|force-reload)
        start_scan
        [[ -f /usr/sbin/scan_network.pl ]] && [[ $ENABLE_DAEMON = "true" ]] && /usr/sbin/scan_network.pl 2>/dev/null 1>/dev/null
        ;;
    stop|shutdown)
        stop_scan
        ;;
    *)
        echo "Usage: scan_network {start|restart|reload|force-reload|stop|shutdown}" >&2
        exit 1
        ;;
esac    

exit 0
#) 2>&1 | tee -a $RUNDIR/.debug/scan_network.debug
) 2>/dev/null
